import { Router } from '@angular/router';
import { Component, OnInit, Input } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ConfigStateService, LocalizationService } from '@abp/ng.core';
import { EditState } from 'joy-abpui-angular';
import { UniqueCodeSettingService } from '../../core/unique-code-setting/unique-code-setting.service';
import { PurchaseOrderDto, PurchaseOrderService, PurchaseOrderLineDto } from '../../proxy/joy/erp/basic-archives/procurements';
import { PurchaseOrderTypeDto } from '../../proxy/joy/erp/basic-archives/procurements/models';
import { PurchaseOrderTypeService } from '../../proxy/joy/erp/basic-archives/procurements/purchase-order-type.service';
import { SupplierDto } from '../../proxy/joy/erp/basic-archives/suppliers/models';
import { SupplierService } from '../../proxy/joy/erp/basic-archives/suppliers/supplier.service';
import { OperatorDto } from '../../proxy/joy/erp/basic-archives/staff/models';
import { OperatorService } from '../../proxy/joy/erp/basic-archives/staff/operator.service';
import { ItemMasterDto } from '../../proxy/joy/erp/basic-archives/item-masters/models';
import { ItemMasterService } from '../../proxy/joy/erp/basic-archives/item-masters/item-master.service';
import { AuxiliaryUnitDto } from '../../proxy/joy/erp/basic-archives/item-masters/models';
import { UnitGroupService } from '../../proxy/joy/erp/basic-archives/item-masters/unit-group.service';
import { PurchaseOrderTypeRefSelectService } from '../purchase-order-type-ref-select/purchase-order-type-ref-select.services';
import { SupplierRefSelectService } from '../../suppliers/supplier-ref-select/supplier-ref-select.services';
import { OperatorRefSelectService } from '../../staff/operator-ref-select/operator-ref-select.services';
import { ItemMasterRefSelectService } from '../../item-masters/item-master-ref-select/item-master-ref-select.services';
import { UnitGroupRefChildrenSelectService } from '../../item-masters/unit-group-ref-children-select/unit-group-ref-children-select.services';
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';
import { map } from 'rxjs/operators';
import { DocumentStatus } from '../../proxy/joy/erp/basic-archives/core';
import { DatePipe } from '@angular/common';
import { Observable } from 'rxjs';
import { debounce } from '../../core/debounce.util';

@Component({
  selector: 'lib-purchase-order-daw-document',
  templateUrl: './purchase-order-daw-document.component.html',
  styleUrls: ['./purchase-order-daw-document.component.less'],
})
export class PurchaseOrderDawDocumentComponent implements OnInit {
  datePipe = new DatePipe('zh-CN');
  entityConfig = {
    defaultValue: {
      businessDate : this.datePipe.transform(new Date(), 'yyyy-MM-dd')
    },
  };

  @Input() id?: string;

  editState: EditState;
  validateForm: FormGroup;
  currentEntity: PurchaseOrderDto;
  readonlyMode: boolean = false;

  get codeInputDisabled() {
    var uniqueCodeConfigration = this.config.getSetting("UniqueCodeConfigration:Joy.Erp.BasicArchives.Procurements.PurchaseOrder");
    var uniqueCodeConfigrationObj = JSON.parse(uniqueCodeConfigration);
    return uniqueCodeConfigrationObj["AutoCode"];
  }

  showOrderTypeSelect = (selectedOrderType: PurchaseOrderTypeDto) => {
    var modalRef = this.purchaseOrderTypeRefSelectService.show(selectedOrderType ? [selectedOrderType] : [], { multiple: false });

    return modalRef.afterClose.pipe(
      map(selectedOrderTypes => {
        if (selectedOrderTypes && selectedOrderTypes.length > 0) {
          return selectedOrderTypes[0];
        }
        return null;
      })
    );
  }

  getOrderTypeDetail = (orderTypeId: string) => {
    return this.purchaseOrderTypeService.get(orderTypeId);
  }

  showSupplierSelect = (selectedSupplier: SupplierDto) => {
    var modalRef = this.supplierRefSelectService.show(selectedSupplier ? [selectedSupplier] : [], { multiple: false });

    return modalRef.afterClose.pipe(
      map((selectedSuppliers: SupplierDto[]) => {
        if (selectedSuppliers && selectedSuppliers.length > 0) {
          return selectedSuppliers[0];
        }
        return null;
      })
    );
  }

  getSupplierDetail = (supplierId: string) => {
    return this.supplierService.get(supplierId);
  }

  showOperatorSelect = (selectedOperator: OperatorDto) => {
    var modalRef = this.operatorRefSelectService.show(selectedOperator ? [selectedOperator] : [], { multiple: false });

    return modalRef.afterClose.pipe(
      map((selectedOperators: OperatorDto[]) => {
        if (selectedOperators && selectedOperators.length > 0) {
          return selectedOperators[0];
        }
        return null;
      })
    );
  }

  getOperatorDetail = (operatorId: string) => {
    return this.operatorService.get(operatorId);
  }

  showItemMasterSelect = (selectedItemMaster: ItemMasterDto) => {
    var modalRef = this.itemMasterRefSelectService.show(selectedItemMaster ? [selectedItemMaster] : [], { multiple: false });

    return modalRef.afterClose.pipe(
      map((selectedItemMasters: ItemMasterDto[]) => {
        if (selectedItemMasters && selectedItemMasters.length > 0) {
          return selectedItemMasters[0];
        }
        return null;
      })
    );
  }

  getItemMasterDetail = (itemMasterId: string) => {
    return this.itemMasterService.get(itemMasterId);
  }

  getShowUnitSelect(child) : (selectedUnit: AuxiliaryUnitDto) => Observable<AuxiliaryUnitDto> {
    return (selectedUnit: AuxiliaryUnitDto) => {
      var modalRef = this.unitGroupRefChildrenSelectService.show(selectedUnit ? [selectedUnit] : [], { 
        multiple: false,
        unitGroupId: child.value.unitGroupId
      });
  
      return modalRef.afterClose.pipe(
        map((selectedUnits: AuxiliaryUnitDto[]) => {
          if (selectedUnits && selectedUnits.length > 0) {
            return selectedUnits[0];
          }
          return null;
        })
      );
    }
  }

  getUnitDetail = (unitId: string) => {
    return this.unitGroupService.getChild(unitId);
  }

  onItemMasterSelect = (itemMaster: ItemMasterDto, childFormGroup: FormGroup) => {
    if (itemMaster) {
      childFormGroup.patchValue({
        itemCode: itemMaster.code,
        itemName: itemMaster.name,
        itemSpec: itemMaster.spec,
        unitGroupId: itemMaster.unitGroupId
      });

      // 如果计量单位为空，则获取料品计量单位组的主计量对应的 AuxiliaryUnit
      const currentUnitId = childFormGroup.get('unitId')?.value;
      if (!currentUnitId && itemMaster.unitGroup && itemMaster.unitGroup.children) {
        // 从 children 中找到 unitId 与 mainUnitId 相同的 AuxiliaryUnit
        const mainAuxiliaryUnit = itemMaster.unitGroup.children.find(
          child => child.unitId === itemMaster.unitGroup.mainUnitId
        );
        
        if (mainAuxiliaryUnit) {
          childFormGroup.patchValue({
            unitId: mainAuxiliaryUnit.id
          });
        }
      }
    }
  }

  onUnitSelect = (unit: AuxiliaryUnitDto, childFormGroup: FormGroup) => {
    if (unit) {
      childFormGroup.patchValue({
        unitId: unit.id
      });
    }
  }

  get children(): FormArray {
    return this.validateForm.get('children') as FormArray;
  }

  /**
   * 获取下一个行号
   * 默认从10开始，步长为10
   */
  getNextLineNo(): number {
    const existingLineNos = this.children.controls
      .map(control => control.get('lineNo')?.value)
      .filter(lineNo => lineNo && lineNo > 0)
      .sort((a, b) => a - b);
    
    if (existingLineNos.length === 0) {
      return 10; // 默认从10开始
    }
    
    // 找到最大的行号，然后加10
    const maxLineNo = Math.max(...existingLineNos);
    return maxLineNo + 10;
  }

  constructor(
    public router: Router,
    public fb: FormBuilder,
    public config: ConfigStateService,
    public message: NzMessageService,
    public modal: NzModalService,
    public modalService: NzModalService,
    public localizationService: LocalizationService,
    public purchaseOrderTypeService: PurchaseOrderTypeService,
    public supplierService: SupplierService,
    public operatorService: OperatorService,
    public itemMasterService: ItemMasterService,
    public entityService: PurchaseOrderService,
    private purchaseOrderTypeRefSelectService: PurchaseOrderTypeRefSelectService,
    private supplierRefSelectService: SupplierRefSelectService,
    private operatorRefSelectService: OperatorRefSelectService,
    private itemMasterRefSelectService: ItemMasterRefSelectService,
    private unitGroupRefChildrenSelectService: UnitGroupRefChildrenSelectService,
    private nzContextMenuService: NzContextMenuService,
    private uniqueCodeSettingService: UniqueCodeSettingService,
    private unitGroupService: UnitGroupService,
  ) {}

  ngOnInit(): void {
    this.editState = EditState.Empty;
    this.currentEntity = this.entityConfig.defaultValue as PurchaseOrderDto;
    this.validateForm = this.fb.group({
      code: [this.entityConfig.defaultValue['code'], [Validators.required, Validators.maxLength(200)]],
      orderTypeId: [this.entityConfig.defaultValue['orderTypeId'], [Validators.required]],
      businessDate: [this.entityConfig.defaultValue['businessDate'], [Validators.required]],
      supplierId: [this.entityConfig.defaultValue['supplierId']],
      operatorId: [this.entityConfig.defaultValue['operatorId']],
      mark: [this.entityConfig.defaultValue['mark'], [Validators.maxLength(2000)]],
      children: this.fb.array([])
    });    
    this.updateCodeValidators();

    if (this.id) {
      this.entityService.get(this.id).subscribe(entity => {
        if (entity) {
          this.setCurrentEntity(entity);
        }
      });
    }

    this.validateForm.valueChanges.subscribe(_ => {
      if (this.editState == EditState.Empty) {
        this.editState = EditState.Creating;
      } else if (this.editState == EditState.View) {
        this.editState = EditState.Editing;
      }
    });
    
    this.updateCodeValidators();
  }

  createChildFormGroup(child?: PurchaseOrderLineDto) {
    return this.fb.group({
      id: [child?.id],
      documentId: [this.currentEntity?.id],
      lineNo: [child?.lineNo || this.getNextLineNo(), [Validators.required, Validators.min(1)]],
      itemMasterId: [child?.itemMasterId, [Validators.required]],
      itemCode: [child?.itemCode, [Validators.required, Validators.maxLength(200)]],
      itemName: [child?.itemName, [Validators.required, Validators.maxLength(200)]],
      itemSpec: [child?.itemSpec, [Validators.maxLength(200)]],
      quantity: [child?.quantity, [Validators.required]],
      unitId: [child?.unitId, [Validators.required]],
      unitPrice: [child?.unitPrice, [Validators.required]],
      deliveryDate: [child?.deliveryDate],      
      sourceType: [child?.sourceType],
      sourceKey: [child?.sourceKey],
      lastModificationTime: [child?.lastModificationTime],
      lastModifierId: [child?.lastModifierId],
      creationTime: [child?.creationTime],
      creatorId: [child?.creatorId],
      unitGroupId: [child?.itemMaster?.unitGroupId]
    });
  }

  addChild() {
    this.children.push(this.createChildFormGroup());
  }

  removeChild(index: number) {
    if (index >= 0 && index < this.children.controls.length) {
      this.children.removeAt(index);
    }
  }

  @debounce()
  save() {
    // 检查整个表单的验证状态
    if (this.validateForm.invalid) {
      // 标记所有控件为已触摸状态，触发验证显示
      this.markFormGroupTouched(this.validateForm);
      this.message.error(this.l('BasicArchives::UI:Message.ValidationError'));
      return;
    }

    // 检查子表单的验证状态
    if (this.children.invalid) {
      this.markFormGroupTouched(this.validateForm);
      this.message.error('请检查子表单的验证错误');
      return;
    }

    if (this.editState == EditState.Creating) {
      this.entityService
        .create({ ...this.validateForm.value })
        .subscribe(entity => {
          if (!!entity) {
            this.setCurrentEntity(entity);
            this.message.success(this.l('BasicArchives::UI:Message.AddSuccess'));
          }
        });
    } else if (this.editState == EditState.Editing) {
      this.entityService
        .update(this.currentEntity.id, {
          ...this.currentEntity,
          ...this.validateForm.value
        })
        .subscribe(entity => {
          if (!!entity) {
            this.setCurrentEntity(entity);
            this.message.success(this.l('BasicArchives::UI:Message.EditSuccess'));
          }
        });
    }
  }

  @debounce()
  giveup() {
    this.giveUpConfirm().then(_ => {
      if (this.editState == EditState.Creating) {
        //表单状态为创建时，清空数据
        this.changeToEmpty();
      } else if (this.editState == EditState.Editing) {
        //表单状态为编辑时，恢复原数据
        this.setCurrentEntity(this.currentEntity);
      }
    });
  }

  @debounce()
  new() {
    this.checkDirty().then(_ => this.changeToEmpty());
  }

  @debounce()
  copy() {
    this.checkDirty().then(_ => {
      this.setCurrentEntity({...this.currentEntity, code: ""});
      this.currentEntity = this.entityConfig.defaultValue as PurchaseOrderDto;
      this.editState = EditState.Creating;
    });
  }

  @debounce()
  delete() {
    this.modal.confirm({
      nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
      nzContent: this.l('BasicArchives::UI:Confirm.Content.DeleteConfirm'),
      nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
      nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
      nzOnOk: () => {
        this.entityService.delete(this.currentEntity.id).subscribe(_ => this.changeToEmpty());
      },
    });
  }

  @debounce()
  submit() {
    if (!this.currentEntity?.id) {
      this.message.warning(this.l('BasicArchives::UI:Document.Message.NeedSave'));
      return;
    }
    this.entityService.submit(this.currentEntity.id).subscribe(() => {
      this.message.success(this.l('BasicArchives::UI:Document.Message.SubmitSuccess'));
      this.refresh();
    });
  }

  @debounce()
  approve() {
    if (!this.currentEntity?.id) {
      this.message.warning(this.l('BasicArchives::UI:Document.Message.NeedSave'));
      return;
    }
    this.entityService.approve(this.currentEntity.id).subscribe(() => {
      this.message.success(this.l('BasicArchives::UI:Document.Message.ApproveSuccess'));
      this.refresh();
    });
  }

  @debounce()
  unapprove() {
    if (!this.currentEntity?.id) {
      this.message.warning(this.l('BasicArchives::UI:Document.Message.NeedSave'));
      return;
    }
    this.entityService.unApprove(this.currentEntity.id).subscribe(() => {
      this.message.success(this.l('BasicArchives::UI:Document.Message.UnApproveSuccess'));
      this.refresh();
    });
  }

  @debounce()
  refresh() {    
    if(this.currentEntity.id) {
      this.entityService.get(this.currentEntity.id).subscribe(entity => {
        if (!!entity) {
          this.setCurrentEntity(entity);
        }
      });
    } else {      
      this.changeToEmpty();
    }
  }

  @debounce()
  search(code) {
    if(code) {
      this.entityService.find(code).subscribe(entity => {
        if (!!entity) {
          this.setCurrentEntity(entity);
        } else {
          this.message.warning(this.l('BasicArchives::UI:Message.CanNotFund', this.l('BasicArchives::ModelTitle:Joy.Erp.BasicArchives.Procurements.PurchaseOrder'), code));
        }
      });
    }
  }

  @debounce()
  uniqueCodeSetting() {
    var settingKey = 'UniqueCodeConfigration:Joy.Erp.BasicArchives.Procurements.PurchaseOrder';
    this.uniqueCodeSettingService.show(settingKey).afterClose.subscribe(result => {
      this.updateCodeValidators();
    });
  }

  contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent): void {
    $event.stopPropagation();
    this.nzContextMenuService.create($event, menu);
  }

  closeMenu(): void {
    this.nzContextMenuService.close();
  }  

  getErrorMessage(fieldName: string): string {
    return this.getControlErrorMessage(this.validateForm, fieldName);
  }

  getControlErrorMessage(formGroup: any, fieldName: string): string {
    const control = formGroup.get(fieldName);
    if (control && control.invalid && (control.touched || control.dirty)) {
      if (control.hasError('required')) {
        return this.l('BasicArchives::UI:Validation:Required');
      }
      if (control.hasError('maxlength')) {
        return this.l('BasicArchives::UI:Validation:MaxLength', control.getError('maxlength').requiredLength);
      }
    }
    return '';
  }

  protected changeToEmpty() {
    this.validateForm.reset({...this.entityConfig.defaultValue, children: []}, { emitEvent: false });
    this.validateForm.setControl('children', this.fb.array([]));
    this.refreshFormValidationStatus();
    this.editState = EditState.Empty;
  }

  protected setCurrentEntity(entity: PurchaseOrderDto) {
    this.currentEntity = entity;
    
    // 对子项按行号排序
    const sortedChildren = entity.children
      .slice()
      .sort((a, b) => {
        const lineNoA = a.lineNo || 0;
        const lineNoB = b.lineNo || 0;
        return lineNoA - lineNoB;
      });
    
    var childrenFromGroups = sortedChildren.map(child => this.createChildFormGroup(child));
    this.validateForm.reset({
      ...this.currentEntity,
      children: []
    }, { emitEvent: false });

    this.validateForm.setControl('children', this.fb.array(childrenFromGroups));
    this.refreshFormValidationStatus();
    if(this.currentEntity.documentStatus == DocumentStatus.Open) {
      this.editState = EditState.View;
      this.readonlyMode = false;
    } else if(this.currentEntity.documentStatus == DocumentStatus.Waiting) {
      this.editState = EditState.Appoving;
      this.readonlyMode = true;
    } else if(this.currentEntity.documentStatus == DocumentStatus.Approved) {
      this.editState = EditState.Appoved;
      this.readonlyMode = true;
    } else {
      this.editState = EditState.View;
      this.readonlyMode = false;
    }
  }

  protected giveUpConfirm(): Promise<any> {
    return new Promise((resolve, reject) => {
      if (this.editState != EditState.Creating && this.editState != EditState.Editing)
        return reject();
      this.modal.confirm({
        nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
        nzContent: this.l('BasicArchives::UI:Confirm.Content.GiveUpConfirm'),
        nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
        nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
        nzOnOk: () => resolve(null),
      });
    });
  }

  protected checkDirty(): Promise<any> {
    return new Promise(resolve => {
      if (this.editState == EditState.Creating || this.editState == EditState.Editing) {
        this.modal.confirm({
          nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
          nzContent: this.l('BasicArchives::UI:Confirm.Content.ChangeStateConfirm'),
          nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
          nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
          nzOnOk: () => resolve(null),
        });
      } else {
        resolve(null);
      }
    });
  }
  
  protected refreshFormValidationStatus() {
    Object.keys(this.validateForm.controls).forEach(key => {
      this.validateForm.controls[key].markAsPristine();
      this.validateForm.controls[key].updateValueAndValidity();
    });
  }

  protected updateCodeValidators() {
    const codeControl = this.validateForm.get('code');
    const validators = [Validators.maxLength(200)];
    if (!this.codeInputDisabled) {
      validators.push(Validators.required);
    }
    codeControl.setValidators(validators);
    codeControl.updateValueAndValidity();
  }

  protected markFormGroupTouched(formGroup: FormGroup) {
    Object.keys(formGroup.controls).forEach(key => {
      const control = formGroup.get(key);
      control.markAsTouched();
      control.updateValueAndValidity();
      
      if (control instanceof FormGroup) {
        this.markFormGroupTouched(control);
      } else if (control instanceof FormArray) {
        control.controls.forEach(arrayControl => {
          arrayControl.markAsTouched();
          arrayControl.updateValueAndValidity();
          if (arrayControl instanceof FormGroup) {
            this.markFormGroupTouched(arrayControl);
          }
        });
      }
    });
  }

  protected l(key: string, ...args: any[]): string {
    return this.localizationService.instant(key, ...args);
  }
} 